home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / utility / 252 / dskpcsrc / phoneboo.mod < prev    next >
Text File  |  1988-02-13  |  50KB  |  1,472 lines

  1. IMPLEMENTATION MODULE PhoneBook;
  2.  
  3.  
  4.    (*$S-,$T- turn off stack and range checking *) 
  5.  
  6.    FROM SYSTEM IMPORT ADR, ADDRESS, TSIZE;
  7.    IMPORT M2Conversions;
  8.    IMPORT GEMDOS;
  9.    IMPORT GEMAESbase;
  10.    IMPORT AESApplications;
  11.    IMPORT AESEvents;
  12.    IMPORT AESForms;
  13.    IMPORT AESObjects;
  14.    IMPORT AESGraphics;
  15.    IMPORT Configuration;
  16.    IMPORT Text;
  17.    IMPORT Resource;
  18.    IMPORT Screen;
  19.    IMPORT Icon;
  20.    IMPORT Dialog;
  21.    IMPORT Window;
  22.    IMPORT File;
  23.    IMPORT Clock;
  24.    IMPORT Calendar;
  25.    IMPORT Disk;
  26.  
  27.    CONST
  28.       LogOpenMsgLine1    = "[1][ The log file is not in | drive ";
  29.       PhoneOpenMsgLine1  = "[1][ The phonebook file is not in | drive ";
  30.       OpenMsgLine2       = ":. What would you | like to do?][Retry|Create|Cancel]";
  31.  
  32.       PhoneExistsMsg     = "[3][ The disk already contains | a phonebook file. ][ Cancel ]";
  33.  
  34.       LogExistsMsg       = "[3][ The disk already contains | a log File. ][ Cancel ]";
  35.  
  36.       DiskFullMsg        = "[3][ The disk is full. ][ Cancel ]";
  37.  
  38.       CreateFailMsgLine1 = "[3][ Can't create the file. Make |";
  39.       CreateFailMsgLine2 = " sure that a DeskPak folder | is in drive ";
  40.       CreateFailMsgLine3 = ": and that the | disk is not write protected. ][Cancel]";
  41.  
  42.       Null              = 0;
  43.       NoSelectedEntries = 0;
  44.       CR                = 15C;
  45.       Bell              = 07C;
  46.       NumberSelectors   = 13;
  47.       NumberEntries     = 8;
  48.  
  49.    TYPE
  50.       String1     = ARRAY [0..0] OF CHAR;
  51.       String3     = ARRAY [0..3] OF CHAR;
  52.       String10    = ARRAY [0..9] OF CHAR;
  53.       String35    = ARRAY [0..34] OF CHAR;
  54.       String3Ptr  = POINTER TO String3;
  55.       String35Ptr = POINTER TO String35;
  56.  
  57.    TYPE EntryInfo = RECORD
  58.       RecordHeader          : File.RecordHeaderType;
  59.       Category              : String1;
  60.       NameText              : String35;
  61.       Number                : String35;
  62.       ValidEntry            : BOOLEAN;
  63.       RecordId              : File.RecordIdType;
  64.       RateDayFirst          : CARDINAL;
  65.       RateDayAdditional     : CARDINAL;
  66.       RateEveningFirst      : CARDINAL;
  67.       RateEveningAdditional : CARDINAL;
  68.       RateNightFirst        : CARDINAL;
  69.       RateNightAdditional   : CARDINAL;
  70.    END;
  71.  
  72.    TYPE EntryInfoPtr = POINTER TO EntryInfo;
  73.  
  74.    TYPE SelectorInfo = RECORD
  75.       Letter      : String1;
  76.       ObjectIndex : INTEGER;
  77.       ObjectPtr   : Icon.ObjectPtr;
  78.    END;
  79.  
  80.    TYPE NameInfo = RECORD
  81.       Entry       : EntryInfo;
  82.       ObjectIndex : INTEGER;
  83.       ObjectPtr   : Icon.ObjectPtr;
  84.    END;
  85.  
  86.  
  87.    VAR
  88.       VirginTool       : BOOLEAN;
  89.       WindowAllocated  : BOOLEAN;
  90.       WindowInfo       : Window.Information;
  91.       WindowResource   : INTEGER;
  92.       Selector         : ARRAY [1..NumberSelectors] OF SelectorInfo;
  93.       Category         : CARDINAL;
  94.       Name             : ARRAY [1..NumberEntries] OF NameInfo;
  95.       SelectedEntry    : CARDINAL;
  96.       DialedEntry      : CARDINAL;
  97.       DeletedEntry     : CARDINAL;
  98.       PreviousTime     : CARDINAL;
  99.       ElapsedHours     : CARDINAL;
  100.       ElapsedMinutes   : CARDINAL;
  101.       Cost             : CARDINAL;
  102.       DisplayedTime    : String10;
  103.       DisplayedCost    : String10;
  104.       PhoneDrive       : CHAR;
  105.       PhoneDriveNumber : CARDINAL;
  106.       LogDrive         : CHAR;
  107.       LogDriveNumber   : CARDINAL;
  108.  
  109.    (************************** LOCAL ROUTINE ***************************)
  110.  
  111.    PROCEDURE OpenFile (
  112.       OpenLog         : BOOLEAN;
  113.       VAR LogFileId   : INTEGER;
  114.       VAR PhoneFileId : File.FileIdType ) : BOOLEAN;
  115.  
  116.    CONST
  117.       ReadWrite  = 2;
  118.       NormalFile = 0;
  119.  
  120.    VAR
  121.       FileOpened  : BOOLEAN;
  122.       FileId      : INTEGER;
  123.       Success     : BOOLEAN;
  124.       ErrorMsg    : ARRAY [0..150] OF CHAR;
  125.       Choice      : INTEGER;
  126.  
  127.    BEGIN
  128.       AESGraphics.GrafMouse ( GEMAESbase.HourGlass, NIL );
  129.       FileOpened := FALSE;
  130.       LOOP
  131.          IF OpenLog THEN
  132.             Disk.CheckStatus ( LogDriveNumber );
  133.             GEMDOS.Open ( Configuration.LogFileName, ReadWrite, LogFileId );
  134.             FileOpened := (LogFileId >= GEMDOS.EOK);
  135.          ELSE
  136.             Disk.CheckStatus ( PhoneDriveNumber );
  137.             File.Open ( Configuration.PhoneFileName, GetKey, GetSubKey, PhoneFileId );
  138.             FileOpened := (File.Status = File.EOK);
  139.          END;
  140.          IF FileOpened THEN
  141.             EXIT;
  142.          ELSE
  143.             IF OpenLog THEN
  144.                ErrorMsg := LogOpenMsgLine1;
  145.                Success := Text.ConcatChar ( ErrorMsg, LogDrive, ErrorMsg );
  146.             ELSE
  147.                ErrorMsg := PhoneOpenMsgLine1;
  148.                Success := Text.ConcatChar ( ErrorMsg, PhoneDrive, ErrorMsg );
  149.             END;
  150.             Success := Text.ConcatString ( ErrorMsg, OpenMsgLine2, ErrorMsg );
  151.             AESGraphics.GrafMouse ( GEMAESbase.Arrow, NIL );
  152.             Choice := AESForms.FormAlert ( 1, ErrorMsg );
  153.             AESGraphics.GrafMouse ( GEMAESbase.HourGlass, NIL );
  154.  
  155.             IF Choice = 1 THEN
  156.                (* Stay in loop and try again *)
  157.  
  158.             ELSIF Choice = 2 THEN
  159.  
  160.                (*--- Make sure that the file doesnt exist -------------*)
  161.  
  162.                IF OpenLog THEN
  163.                   Disk.CheckStatus ( LogDriveNumber );
  164.                   GEMDOS.Open ( Configuration.LogFileName, ReadWrite, FileId );
  165.                   FileOpened := (FileId >= GEMDOS.EOK);
  166.                   IF FileOpened THEN
  167.                      AESGraphics.GrafMouse ( GEMAESbase.Arrow, NIL );
  168.                      Choice  := AESForms.FormAlert ( 1, LogExistsMsg );
  169.                   END;
  170.                ELSE
  171.                   Disk.CheckStatus ( PhoneDriveNumber );
  172.                   GEMDOS.Open ( Configuration.PhoneFileName, ReadWrite, FileId );
  173.                   FileOpened := (FileId >= GEMDOS.EOK);
  174.                   IF FileOpened THEN
  175.                      AESGraphics.GrafMouse ( GEMAESbase.Arrow, NIL );
  176.                      Choice  := AESForms.FormAlert ( 1, PhoneExistsMsg );
  177.                   END;
  178.                END;
  179.                IF FileOpened THEN
  180.                   Success    := GEMDOS.Close ( FileId );
  181.                   FileOpened := FALSE;
  182.                ELSE (* NOT FileOpened *)
  183.  
  184.                   (*--- The file doesnt exist, so try to create it ----*)
  185.  
  186.                   IF OpenLog THEN
  187.                      GEMDOS.Create ( Configuration.LogFileName, NormalFile, LogFileId );
  188.                      FileOpened := (LogFileId >= GEMDOS.EOK);
  189.                   ELSE
  190.                      File.Create (
  191.                         Configuration.PhoneFileName, 
  192.                         TSIZE (EntryInfo),
  193.                         GetKey,
  194.                         GetSubKey,
  195.                         PhoneFileId );
  196.                      FileOpened := (File.Status = File.EOK);
  197.                   END;
  198.                   IF NOT FileOpened THEN
  199.                      ErrorMsg := CreateFailMsgLine1;
  200.                      Success  := Text.ConcatString (
  201.                         ErrorMsg, CreateFailMsgLine2, ErrorMsg );
  202.                      IF OpenLog THEN
  203.                         Success  := Text.ConcatChar (
  204.                            ErrorMsg, LogDrive, ErrorMsg );
  205.                      ELSE
  206.                         Success  := Text.ConcatChar (
  207.                            ErrorMsg, PhoneDrive, ErrorMsg );
  208.                      END;
  209.                      Success  := Text.ConcatString (
  210.                         ErrorMsg, CreateFailMsgLine3, ErrorMsg );
  211.                      AESGraphics.GrafMouse ( GEMAESbase.Arrow, NIL );
  212.                      Choice := AESForms.FormAlert ( 1, ErrorMsg );
  213.                   END;
  214.                END;
  215.                EXIT;
  216.             ELSE (* Choice = 3 *)
  217.                EXIT;
  218.             END;
  219.          END;
  220.       END; (* LOOP *)
  221.       RETURN (FileOpened);
  222.    END OpenFile;
  223.  
  224.    (************************** LOCAL ROUTINE ***************************)
  225.  
  226.    PROCEDURE GetKey ( Data    : ADDRESS;
  227.                       VAR Key : ARRAY OF CHAR );
  228.  
  229.    VAR Entry : EntryInfoPtr;
  230.  
  231.    BEGIN
  232.       Entry := EntryInfoPtr (Data);
  233.       Text.Assign ( Entry^.Category, Key );
  234.    END GetKey;
  235.  
  236.    (************************** LOCAL ROUTINE ***************************)
  237.  
  238.    PROCEDURE GetSubKey ( Data       : ADDRESS;
  239.                          VAR SubKey : ARRAY OF CHAR );
  240.  
  241.    VAR Entry : EntryInfoPtr;
  242.  
  243.    BEGIN
  244.       Entry := EntryInfoPtr (Data);
  245.       Text.Assign ( Entry^.NameText, SubKey );
  246.    END GetSubKey;
  247.  
  248.    (************************** LOCAL ROUTINE ***************************)
  249.  
  250.    PROCEDURE ReadPhoneBook (
  251.       ValidId : BOOLEAN;
  252.       EntryId : File.RecordIdType;
  253.       Redraw  : BOOLEAN );
  254.  
  255.    CONST
  256.       PhoneBookFile       = FALSE;
  257.       EmptyLine           = "___________________________________";
  258.  
  259.    VAR
  260.       LogFileId      : INTEGER;
  261.       PhoneFileId    : File.FileIdType;
  262.       NextEntry      : EntryInfo;
  263.       FoundRecord    : BOOLEAN;
  264.       FileOpened     : BOOLEAN;
  265.       Index          : CARDINAL;
  266.       WorkBuffer     : EntryInfo;
  267.       RecordId       : File.RecordIdType;
  268.       Success        : BOOLEAN;
  269.       FirstLetter    : CHAR;
  270.       SecondLetter   : CHAR;
  271.  
  272.    BEGIN
  273.       FoundRecord := FALSE;
  274.  
  275.       (*--- Turn off the current selector -----------------------------*)
  276.  
  277.       Selector[Category].ObjectPtr^.State :=
  278.          Selector[Category].ObjectPtr^.State - {Icon.Selected};
  279.       IF Redraw THEN
  280.          Icon.Display (
  281.             Resource.D6PHONE,
  282.             Selector[Category].ObjectIndex,
  283.             WindowInfo.Borders );
  284.       END;
  285.  
  286.       (*--- Open the phonebook file -----------------------------------*)
  287.  
  288.       IF ValidId THEN
  289.          FileOpened := OpenFile ( PhoneBookFile, LogFileId, PhoneFileId );
  290.       ELSE
  291.          FileOpened := FALSE;
  292.       END;
  293.       IF FileOpened THEN
  294.      
  295.          (*--- Get the first record -----------------------------------*)
  296.  
  297.          IF EntryId = Null THEN  (* Start at the beginning of the file *)
  298.             File.Read ( PhoneFileId, ADR (NextEntry), RecordId );
  299.          ELSE
  300.             File.Seek ( PhoneFileId, EntryId, ADR (NextEntry) );
  301.             RecordId := EntryId;
  302.          END;
  303.          IF File.Status = File.EOK THEN
  304.  
  305.             (*--- Determine the current category ----------------------*)
  306.  
  307.             FoundRecord := TRUE;
  308.             Category := 1;
  309.             LOOP
  310.                FirstLetter  := Selector[Category].Letter[0];
  311.                SecondLetter := CHR (ORD (FirstLetter) + 1);
  312.                IF (NextEntry.Category[0] = FirstLetter) OR
  313.                   (NextEntry.Category[0] = SecondLetter) THEN
  314.                   EXIT;
  315.                END;
  316.                INC (Category);
  317.                IF Category > NumberSelectors THEN
  318.                   DEC (Category);
  319.                   EXIT;
  320.                END;
  321.             END (* LOOP *);
  322.          END;
  323.       END;
  324.  
  325.       (*--- Read in the remaining entries -----------------------------*)
  326.  
  327.       Index := 1;
  328.       LOOP
  329.          IF FileOpened AND
  330.                (File.Status = File.EOK) AND
  331.                ((NextEntry.Category[0] = FirstLetter) OR
  332.                (NextEntry.Category[0] = SecondLetter)) THEN
  333.             Name[Index].Entry := NextEntry;
  334.             Name[Index].Entry.ValidEntry := TRUE;
  335.             Name[Index].Entry.RecordId   := RecordId;
  336.          ELSE
  337.             Name[Index].Entry.ValidEntry := FALSE;
  338.             Name[Index].Entry.NameText   := EmptyLine;
  339.          END;
  340.          INC ( Index );
  341.          IF Index <= NumberEntries THEN
  342.             IF FileOpened THEN  (* Get next record from file *)
  343.                File.Read ( PhoneFileId, ADR (NextEntry), RecordId );
  344.             END;
  345.          ELSE
  346.             EXIT;
  347.          END;
  348.       END; (* LOOP *)
  349.  
  350.       (*--- Close the phonebook file ----------------------------------*)
  351.  
  352.       IF FileOpened THEN
  353.          File.Close ( PhoneFileId );
  354.       END;
  355.  
  356.       (*--- Highlight the current selector ----------------------------*)
  357.  
  358.       IF FoundRecord THEN
  359.          Selector[Category].ObjectPtr^.State :=
  360.             Selector[Category].ObjectPtr^.State + {Icon.Selected};
  361.       END;
  362.       IF Redraw THEN
  363.          Icon.Display (
  364.             Resource.D6PHONE,
  365.             Selector[Category].ObjectIndex,
  366.             WindowInfo.Borders );
  367.          Icon.Display (
  368.             Resource.D6PHONE,
  369.             Resource.D6NUMBRS,
  370.             WindowInfo.Borders );
  371.       END;
  372.    END ReadPhoneBook;
  373.  
  374.    (************************** LOCAL ROUTINE ***************************)
  375.  
  376.    PROCEDURE EditEntry ( VAR Item : EntryInfo );
  377.  
  378.    TYPE TedInfoPtrType = POINTER TO Icon.Tedinfo;
  379.  
  380.    VAR
  381.       ObjectPtr             : Icon.ObjectPtr;
  382.       TedInfoPtr            : TedInfoPtrType;
  383.       NamePtr               : String35Ptr;
  384.       NumberPtr             : String35Ptr;
  385.       RateDayFirst          : String3Ptr;
  386.       RateDayAdditional     : String3Ptr;
  387.       RateEveningFirst      : String3Ptr;
  388.       RateEveningAdditional : String3Ptr;
  389.       RateNightFirst        : String3Ptr;
  390.       RateNightAdditional   : String3Ptr;
  391.       Success               : BOOLEAN;
  392.       CaseConversion        : CARDINAL;
  393.  
  394.    BEGIN
  395.  
  396.       (*--- Save the addresses of the various dialog box objects -------*)
  397.  
  398.       ObjectPtr  := Icon.GetAddress ( Resource.D7PHINFO, Resource.D7NAME );
  399.       TedInfoPtr := TedInfoPtrType (ObjectPtr^.Spec);
  400.       NamePtr    := String35Ptr (TedInfoPtr^.Text);
  401.  
  402.       ObjectPtr  := Icon.GetAddress ( Resource.D7PHINFO, Resource.D7NUMBER );
  403.       TedInfoPtr := TedInfoPtrType (ObjectPtr^.Spec);
  404.       NumberPtr  := String35Ptr (TedInfoPtr^.Text);
  405.  
  406.       ObjectPtr  := Icon.GetAddress ( Resource.D7PHINFO, Resource.D7FDAY );
  407.       TedInfoPtr := TedInfoPtrType (ObjectPtr^.Spec);
  408.       RateDayFirst := String3Ptr (TedInfoPtr^.Text);
  409.  
  410.       ObjectPtr  := Icon.GetAddress ( Resource.D7PHINFO, Resource.D7EDAY );
  411.       TedInfoPtr := TedInfoPtrType (ObjectPtr^.Spec);
  412.       RateDayAdditional := String3Ptr (TedInfoPtr^.Text);
  413.  
  414.       ObjectPtr  := Icon.GetAddress ( Resource.D7PHINFO, Resource.D7FEVEN );
  415.       TedInfoPtr := TedInfoPtrType (ObjectPtr^.Spec);
  416.       RateEveningFirst := String3Ptr (TedInfoPtr^.Text);
  417.  
  418.       ObjectPtr  := Icon.GetAddress ( Resource.D7PHINFO, Resource.D7EEVEN );
  419.       TedInfoPtr := TedInfoPtrType (ObjectPtr^.Spec);
  420.       RateEveningAdditional := String3Ptr (TedInfoPtr^.Text);
  421.  
  422.       ObjectPtr  := Icon.GetAddress ( Resource.D7PHINFO, Resource.D7FNIGHT );
  423.       TedInfoPtr := TedInfoPtrType (ObjectPtr^.Spec);
  424.       RateNightFirst := String3Ptr (TedInfoPtr^.Text);
  425.  
  426.       ObjectPtr  := Icon.GetAddress ( Resource.D7PHINFO, Resource.D7ENIGHT );
  427.       TedInfoPtr := TedInfoPtrType (ObjectPtr^.Spec);
  428.       RateNightAdditional := String3Ptr (TedInfoPtr^.Text);
  429.  
  430.       (*--- Initialize the dialog box objects --------------------------*)
  431.  
  432.       Text.Assign ( Item.NameText, NamePtr^ );
  433.       Text.Assign ( Item.Number, NumberPtr^ );
  434.       M2Conversions.ConvertCardinal (
  435.          Item.RateDayFirst, 3, RateDayFirst^ );
  436.       M2Conversions.ConvertCardinal (
  437.          Item.RateDayAdditional, 3, RateDayAdditional^ );
  438.       M2Conversions.ConvertCardinal (
  439.          Item.RateEveningFirst, 3, RateEveningFirst^ );
  440.       M2Conversions.ConvertCardinal (
  441.          Item.RateEveningAdditional, 3, RateEveningAdditional^ );
  442.       M2Conversions.ConvertCardinal (
  443.          Item.RateNightFirst, 3, RateNightFirst^ );
  444.       M2Conversions.ConvertCardinal (
  445.          Item.RateNightAdditional, 3, RateNightAdditional^ );
  446.  
  447.       (*--- Invoke the dialog ------------------------------------------*)
  448.  
  449.       Item.ValidEntry := (Dialog.Display (
  450.          Resource.D7PHINFO, Screen.Center, Resource.D7NAME ) =
  451.          Resource.D7OK);
  452.          
  453.       (*--- Save the results -------------------------------------------*)
  454.  
  455.       Text.Assign ( NamePtr^, Item.NameText );
  456.       Item.Category[0] := Item.NameText[0];
  457.       IF Item.Category[0] > 'Z' THEN
  458.          CaseConversion    := ORD ('a') - ORD ('A');
  459.          Item.Category[0] := CHR (ORD (Item.Category[0]) - CaseConversion);
  460.       END;
  461.       Text.Assign ( NumberPtr^, Item.Number );
  462.       M2Conversions.ConvertToCardinal (
  463.          RateDayFirst^, Success, Item.RateDayFirst );
  464.       M2Conversions.ConvertToCardinal (
  465.          RateDayAdditional^, Success, Item.RateDayAdditional );
  466.       M2Conversions.ConvertToCardinal (
  467.          RateEveningFirst^, Success, Item.RateEveningFirst );
  468.       M2Conversions.ConvertToCardinal (
  469.          RateEveningAdditional^, Success, Item.RateEveningAdditional );
  470.       M2Conversions.ConvertToCardinal (
  471.          RateNightFirst^, Success, Item.RateNightFirst );
  472.       M2Conversions.ConvertToCardinal (
  473.          RateNightAdditional^, Success, Item.RateNightAdditional );
  474.    END EditEntry;
  475.  
  476.    (************************** LOCAL ROUTINE ***************************)
  477.  
  478.    PROCEDURE EnableDialDelete;
  479.  
  480.    VAR ObjectPtr : Icon.ObjectPtr;
  481.  
  482.    BEGIN
  483.       ObjectPtr := Icon.GetAddress ( Resource.D6PHONE, Resource.D6DIAL );
  484.       ObjectPtr^.State := ObjectPtr^.State - {Icon.Disabled};
  485.       Icon.Display ( Resource.D6PHONE, Resource.D6DIAL, WindowInfo.Borders );
  486.  
  487.       ObjectPtr := Icon.GetAddress ( Resource.D6PHONE, Resource.D6DELETE );
  488.       ObjectPtr^.State := ObjectPtr^.State - {Icon.Disabled};
  489.       Icon.Display ( Resource.D6PHONE, Resource.D6DELETE, WindowInfo.Borders );
  490.    END EnableDialDelete;
  491.  
  492.    (************************** LOCAL ROUTINE ***************************)
  493.  
  494.    PROCEDURE DisableDialDelete;
  495.  
  496.    VAR ObjectPtr : Icon.ObjectPtr;
  497.  
  498.    BEGIN
  499.       ObjectPtr := Icon.GetAddress ( Resource.D6PHONE, Resource.D6DIAL );
  500.       ObjectPtr^.State := ObjectPtr^.State + {Icon.Disabled};
  501.       Icon.Display ( Resource.D6PHONE, Resource.D6DIAL, WindowInfo.Borders );
  502.  
  503.       ObjectPtr := Icon.GetAddress ( Resource.D6PHONE, Resource.D6DELETE );
  504.       ObjectPtr^.State := ObjectPtr^.State + {Icon.Disabled};
  505.       Icon.Display ( Resource.D6PHONE, Resource.D6DELETE, WindowInfo.Borders );
  506.    END DisableDialDelete;
  507.  
  508.    (************************** LOCAL ROUTINE ***************************)
  509.  
  510.    PROCEDURE DeselectEntries ();
  511.  
  512.    VAR ObjectPtr : Icon.ObjectPtr;
  513.  
  514.    BEGIN
  515.       IF SelectedEntry = NoSelectedEntries THEN
  516.          ; (* Do nothing, since nothing is selected *)
  517.       ELSE
  518.          Name[SelectedEntry].ObjectPtr^.State :=
  519.             Name[SelectedEntry].ObjectPtr^.State - {Icon.Selected};
  520.          Icon.Display (
  521.             Resource.D6PHONE,
  522.             Name[SelectedEntry].ObjectIndex,
  523.             WindowInfo.Borders );
  524.          DisableDialDelete;
  525.          SelectedEntry := NoSelectedEntries;
  526.       END;
  527.    END DeselectEntries;
  528.  
  529.    (************************** LOCAL ROUTINE ***************************)
  530.  
  531.    PROCEDURE MinutesSinceLastMark () : CARDINAL;
  532.  
  533.    CONST MinutesPerDay = 1440;
  534.  
  535.    VAR
  536.       Time       : CARDINAL;
  537.       Minutes    : CARDINAL;
  538.       Difference : CARDINAL;
  539.  
  540.    BEGIN
  541.       GEMDOS.GetTime ( Time );
  542.       Minutes := (Time DIV 2048) * 60 + ((Time MOD 2048) DIV 32);
  543.       IF Minutes >= PreviousTime THEN
  544.          Difference := Minutes - PreviousTime;
  545.       ELSE (* Minutes < PreviousTime *)
  546.          Difference := MinutesPerDay - PreviousTime + Minutes;
  547.       END;
  548.       PreviousTime := Minutes;
  549.       RETURN (Difference);
  550.    END MinutesSinceLastMark;
  551.  
  552.    (************************** LOCAL ROUTINE ***************************)
  553.  
  554.    PROCEDURE UpdateTime;
  555.  
  556.    VAR
  557.       Buffer         : String10;
  558.       Success        : BOOLEAN;
  559.       
  560.    BEGIN
  561.       ElapsedMinutes := ElapsedMinutes + MinutesSinceLastMark ();
  562.       IF ElapsedMinutes > 59 THEN
  563.          INC (ElapsedHours, (ElapsedMinutes DIV 60));
  564.          ElapsedMinutes := ElapsedMinutes MOD 60;
  565.       END;
  566.       M2Conversions.ConvertCardinal ( ElapsedHours, 2, DisplayedTime );
  567.       DisplayedTime[2] := ':';
  568.       DisplayedTime[3] := CHR (0);
  569.       M2Conversions.ConvertCardinal ( ElapsedMinutes, 2, Buffer );
  570.       IF Buffer[0] = ' ' THEN
  571.          Buffer[0] := '0';
  572.       END;
  573.       Success := Text.ConcatString ( DisplayedTime, Buffer, DisplayedTime );
  574.    END UpdateTime;
  575.  
  576.    (************************** LOCAL ROUTINE ***************************)
  577.  
  578.    PROCEDURE UpdateCost;
  579.  
  580.    VAR
  581.       RateFirst : CARDINAL;
  582.       RateAddt  : CARDINAL;
  583.       Ticks     : CARDINAL;
  584.       Buffer    : String10;
  585.       Success   : BOOLEAN;
  586.  
  587.    BEGIN
  588.       IF Calendar.DayIsSaturday () OR
  589.             (Calendar.DayIsSunday () AND (NOT Clock.EveningPeriod ())) OR
  590.             Clock.NightPeriod () THEN
  591.          RateFirst := Name[DialedEntry].Entry.RateNightFirst;
  592.          RateAddt  := Name[DialedEntry].Entry.RateNightAdditional;
  593.  
  594.       ELSIF Clock.EveningPeriod () THEN 
  595.          RateFirst := Name[DialedEntry].Entry.RateEveningFirst;
  596.          RateAddt  := Name[DialedEntry].Entry.RateEveningAdditional;
  597.  
  598.       ELSE  (* It must be during the day *)
  599.          RateFirst := Name[DialedEntry].Entry.RateDayFirst;
  600.          RateAddt  := Name[DialedEntry].Entry.RateDayAdditional;
  601.  
  602.       END;
  603.       Ticks := (ElapsedHours * 60) + ElapsedMinutes;
  604.       IF Ticks < 1 THEN
  605.          Cost := 0;
  606.       ELSIF Ticks = 1 THEN
  607.          Cost := RateFirst;
  608.       ELSE (* Ticks > 1 *)
  609.          Cost := RateFirst + (RateAddt * (Ticks - 1));
  610.       END;
  611.       DisplayedCost := "$";
  612.       M2Conversions.ConvertCardinal ( (Cost DIV 100), 2, Buffer );
  613.       Success := Text.ConcatString ( DisplayedCost, Buffer, DisplayedCost );
  614.       DisplayedCost[3] := '.';
  615.       DisplayedCost[4] := CHR (0);
  616.       M2Conversions.ConvertCardinal ( (Cost MOD 100), 2, Buffer );
  617.       IF Buffer[0] = ' ' THEN
  618.          Buffer[0] := '0';
  619.       END;
  620.       Success := Text.ConcatString ( DisplayedCost, Buffer, DisplayedCost );
  621.    END UpdateCost;
  622.  
  623.    (************************** LOCAL ROUTINE ***************************)
  624.  
  625.    PROCEDURE HangUp;
  626.  
  627.    VAR
  628.       ObjectPtr : Icon.ObjectPtr;
  629.       TextPtr   : String35Ptr;
  630.  
  631.    BEGIN
  632.  
  633.       (*--- Restore the components associated with Dialing -------------*)
  634.  
  635.       ObjectPtr := Icon.GetAddress ( Resource.D8PHTIME, Resource.D8DIAL );
  636.       ObjectPtr^.Flags := ObjectPtr^.Flags - {Icon.HideTree};
  637.  
  638.       ObjectPtr := Icon.GetAddress ( Resource.D8PHTIME, Resource.D8COST );
  639.       ObjectPtr^.Flags := ObjectPtr^.Flags - {Icon.HideTree};
  640.  
  641.       ObjectPtr := Icon.GetAddress ( Resource.D8PHTIME, Resource.D8MSG );
  642.       TextPtr   := String35Ptr (ObjectPtr^.Spec);
  643.       TextPtr^  := "Dialing ...";
  644.  
  645.       (*--- Open the phone directory window ----------------------------*) 
  646.  
  647.       Close;   (* Close the time monitor window *)
  648.       WindowResource := Resource.D6PHONE;
  649.       Open;
  650.  
  651.    END HangUp;
  652.  
  653.    (************************** LOCAL ROUTINE ***************************)
  654.  
  655.    PROCEDURE InsertEntry ( Item : EntryInfo );
  656.  
  657.    CONST
  658.       PhoneBookFile = FALSE;
  659.       ValidId       = TRUE;
  660.  
  661.    VAR
  662.       LogFileId   : INTEGER;
  663.       PhoneFileId : File.FileIdType;
  664.       WorkBuffer  : EntryInfo;
  665.       RecordId    : File.RecordIdType;
  666.       InsertOK    : BOOLEAN;
  667.       FoundKey    : BOOLEAN;
  668.       KeyId       : File.RecordIdType;
  669.       FoundRecord : BOOLEAN;
  670.  
  671.    BEGIN
  672.       IF OpenFile ( PhoneBookFile, LogFileId, PhoneFileId ) THEN
  673.          File.InsertRecord (
  674.             PhoneFileId,
  675.             Item.Category,
  676.             Item.NameText,
  677.             ADR (Item),
  678.             ADR (WorkBuffer),
  679.             RecordId );
  680.          InsertOK := (File.Status = File.EOK);
  681.          File.Close ( PhoneFileId );
  682.          IF InsertOK AND OpenFile ( PhoneBookFile, LogFileId, PhoneFileId ) THEN
  683.             File.Find (
  684.                PhoneFileId,
  685.                Item.Category,
  686.                "",
  687.                ADR (WorkBuffer),
  688.                FoundKey,
  689.                KeyId,
  690.                FoundRecord,
  691.                RecordId );
  692.             File.Close ( PhoneFileId );
  693.             ReadPhoneBook ( FoundKey, KeyId, TRUE );
  694.          END;
  695.       END;
  696.    END InsertEntry;
  697.  
  698.    (************************** LOCAL ROUTINE ***************************)
  699.  
  700.    PROCEDURE ProcessName ( EntryIndex : CARDINAL;
  701.                            Clicks     : INTEGER );
  702.  
  703.    CONST PhoneBookFile = FALSE;
  704.  
  705.    VAR
  706.       LogFileId   : INTEGER;
  707.       PhoneFileId : File.FileIdType;
  708.       ObjectPtr   : Icon.ObjectPtr;
  709.       Item        : EntryInfo;
  710.       WorkBuffer  : EntryInfo;
  711.  
  712.    BEGIN
  713.       DeselectEntries;
  714.       IF Name[EntryIndex].Entry.ValidEntry THEN
  715.          IF Clicks = 1 THEN
  716.  
  717.             (*--- The user single clicked, so select the entry ---------*)
  718.  
  719.             Name[EntryIndex].ObjectPtr^.State :=
  720.                Name[EntryIndex].ObjectPtr^.State + {Icon.Selected};
  721.             Icon.Display (
  722.                Resource.D6PHONE,
  723.                Name[EntryIndex].ObjectIndex,
  724.                WindowInfo.Borders );
  725.             SelectedEntry := EntryIndex;
  726.             EnableDialDelete;
  727.          ELSE
  728.  
  729.             (*--- The user double clicked, so edit the entry -----------*)
  730.  
  731.             Item := Name[EntryIndex].Entry;
  732.             EditEntry ( Item );
  733.             IF Item.ValidEntry THEN
  734.  
  735.                (* TBD - May want to see if the key has been modified. *)
  736.                (* If not, simply update the information by using      *)
  737.                (* File.Write.  If the keys are not the same, the      *)
  738.                (* record must be deleted and reinserted as usual.     *)
  739.  
  740.                (*--- Save the new information on disk ------------------*)
  741.  
  742.                IF OpenFile ( PhoneBookFile, LogFileId, PhoneFileId ) THEN
  743.                   File.DeleteRecord (   
  744.                      PhoneFileId,
  745.                      Name[EntryIndex].Entry.RecordId,
  746.                      ADR (WorkBuffer) );
  747.                   File.Close ( PhoneFileId );
  748.                   InsertEntry ( Item );
  749.                END;
  750.             END;
  751.          END;
  752.       ELSE
  753.          GEMDOS.ConOut ( Bell );
  754.       END;
  755.    END ProcessName;
  756.  
  757.    (************************** LOCAL ROUTINE ***************************)
  758.  
  759.    PROCEDURE TimeCall;
  760.  
  761.    VAR ObjectPtr : Icon.ObjectPtr;
  762.  
  763.    BEGIN
  764.       Close;   (* Close the phone directory window *)
  765.  
  766.       (*--- Hide the components associated with dialing ---------------*)
  767.  
  768.       ObjectPtr := Icon.GetAddress ( Resource.D8PHTIME, Resource.D8DIAL );
  769.       ObjectPtr^.Flags := ObjectPtr^.Flags + {Icon.HideTree};
  770.       ObjectPtr := Icon.GetAddress ( Resource.D8PHTIME, Resource.D8COST );
  771.       ObjectPtr^.Flags := ObjectPtr^.Flags + {Icon.HideTree};
  772.  
  773.       (*--- Start timing the phone call -------------------------------*)
  774.  
  775.       ElapsedMinutes := MinutesSinceLastMark ();
  776.       ElapsedMinutes := 0;  (* Ignore the previous call *)
  777.       ElapsedHours   := 0;
  778.       DisplayedTime  := " 0:00";
  779.       WindowResource := Resource.D8PHTIME;
  780.       Open;    (* Open the time monitor window *)
  781.    END TimeCall;
  782.  
  783.    (************************** LOCAL ROUTINE ***************************)
  784.  
  785.    PROCEDURE ModemOut ( VAR String : ARRAY OF CHAR ) : BOOLEAN;
  786.  
  787.    VAR
  788.       Index : CARDINAL;
  789.       Ch    : CHAR;
  790.  
  791.    BEGIN
  792.       Index := 0;
  793.       LOOP
  794.  
  795.          (*--- Clear out any characters from the input stream ----------*)
  796.  
  797.          WHILE (GEMDOS.AuxIS ()) DO
  798.             GEMDOS.AuxIn ( Ch );
  799.          END;
  800.  
  801.          (*--- Send the character to the modem ---*)
  802.  
  803.          IF NOT GEMDOS.AuxOS () THEN
  804.  
  805.             (*--- The RS-232 port is not ready, so wait 3 seconds ------*)
  806.  
  807.             AESEvents.EventTimer ( 3000, 0 );
  808.             IF NOT GEMDOS.AuxOS () THEN
  809.  
  810.                (*--- Still not ready, so the modem must be off ---------*)
  811.  
  812.                RETURN (FALSE);
  813.             END;
  814.          END;
  815.          IF (Index > HIGH (String)) OR (String[Index] = CHR (0)) THEN
  816.             EXIT;
  817.          END;
  818.          GEMDOS.AuxOut ( String[Index] );
  819.          INC (Index);
  820.       END (* LOOP *);
  821.       RETURN (TRUE);
  822.    END ModemOut;
  823.  
  824.    (************************** LOCAL ROUTINE ***************************)
  825.  
  826.    PROCEDURE Dial;
  827.  
  828.    TYPE TedInfoPtrType = POINTER TO Icon.Tedinfo;
  829.  
  830.    VAR
  831.       ObjectPtr    : Icon.ObjectPtr;
  832.       TedInfoPtr   : TedInfoPtrType;
  833.       NumberPtr    : String35Ptr;
  834.       MsgPtr       : String35Ptr;
  835.       NumberLength : CARDINAL;
  836.       Count        : CARDINAL;
  837.       Success      : BOOLEAN;
  838.       Ch           : CHAR;
  839.       ModemOk      : BOOLEAN;
  840.  
  841.    BEGIN
  842.       Close;   (* Close the directory window *)
  843.  
  844.       (*--- Clear the "number dialed" field ----------------------------*)
  845.  
  846.       ObjectPtr  := Icon.GetAddress ( Resource.D8PHTIME, Resource.D8NUMBER );
  847.       TedInfoPtr := TedInfoPtrType (ObjectPtr^.Spec);
  848.       NumberPtr  := String35Ptr (TedInfoPtr^.Text);
  849.       Text.Assign ( Name[DialedEntry].Entry.Number, NumberPtr^ ); 
  850.  
  851.       (*--- Start timing the phone call --------------------------------*)
  852.  
  853.       ElapsedMinutes := MinutesSinceLastMark ();
  854.       ElapsedMinutes := 0;  (* Ignore the previous call *)
  855.       ElapsedHours   := 0;
  856.       DisplayedTime  := " 0:00";
  857.       DisplayedCost  := "$ 0.00";
  858.       WindowResource := Resource.D8PHTIME;
  859.       Open;    (* Open the time monitor window *)
  860.       Window.Redraw ( WindowInfo.Id, WindowInfo.Borders );
  861.  
  862.       (*--- Dial the number through the modem --------------------------*)
  863.  
  864.       ModemOk := ModemOut ( Configuration.ModemDialPrefix );
  865.       IF ModemOk THEN
  866.          ModemOk := ModemOut ( Name[DialedEntry].Entry.Number );
  867.       END;
  868.       IF ModemOk THEN
  869.          ModemOk := ModemOut ( Configuration.ModemDialSuffix );
  870.       END;
  871.       IF ModemOk THEN
  872.          GEMDOS.AuxOut ( CR );
  873.       END;
  874.  
  875.       (*--- Clear out any characters from the input stream -------------*)
  876.  
  877.       WHILE (GEMDOS.AuxIS ()) DO
  878.          GEMDOS.AuxIn ( Ch );
  879.       END;
  880.  
  881.       (*--- Inform the user that the number has been dialed ------------*)
  882.  
  883.       ObjectPtr := Icon.GetAddress ( Resource.D8PHTIME, Resource.D8MSG );
  884.       MsgPtr    := String35Ptr (ObjectPtr^.Spec);
  885.       MsgPtr^   := "   Dialed :";
  886.    END Dial;
  887.  
  888.    (************************** LOCAL ROUTINE ***************************)
  889.  
  890.    PROCEDURE AddEntry;
  891.  
  892.    VAR
  893.       NewEntry : EntryInfo;
  894.       Choice   : INTEGER;
  895.  
  896.    BEGIN
  897.       AESGraphics.GrafMouse ( GEMAESbase.HourGlass, NIL );
  898.       Disk.CheckStatus ( PhoneDriveNumber );
  899.       IF Disk.SpaceAvailable ( PhoneDriveNumber, LONGCARD (TSIZE (EntryInfo)) ) THEN
  900.          NewEntry.NameText              := CHR (0);
  901.          NewEntry.Number                := CHR (0);
  902.          NewEntry.RateDayFirst          := 0;
  903.          NewEntry.RateDayAdditional     := 0;
  904.          NewEntry.RateEveningFirst      := 0;
  905.          NewEntry.RateEveningAdditional := 0;
  906.          NewEntry.RateNightFirst        := 0;
  907.          NewEntry.RateNightAdditional   := 0;
  908.          AESGraphics.GrafMouse ( GEMAESbase.Arrow, NIL );
  909.          EditEntry ( NewEntry );
  910.          IF NewEntry.ValidEntry THEN
  911.             InsertEntry ( NewEntry );
  912.          END;
  913.       ELSE
  914.          AESGraphics.GrafMouse ( GEMAESbase.Arrow, NIL );
  915.          Choice := AESForms.FormAlert ( 1, DiskFullMsg );
  916.       END;
  917.    END AddEntry;
  918.  
  919.    (************************** LOCAL ROUTINE ***************************)
  920.  
  921.    PROCEDURE DeleteEntry;
  922.  
  923.    CONST
  924.       PhoneBookFile = FALSE;
  925.       ValidId       = TRUE;
  926.  
  927.    VAR
  928.       LogFileId   : INTEGER;
  929.       PhoneFileId : File.FileIdType;
  930.       TopRecordId : File.RecordIdType;
  931.       WorkBuffer  : EntryInfo;
  932.  
  933.    BEGIN
  934.       IF OpenFile ( PhoneBookFile, LogFileId, PhoneFileId ) THEN
  935.  
  936.          (*--- Get the id of the record that will fill the slot --------*)
  937.          (*--- after the selected record has been deleted.      --------*)
  938.  
  939.          IF DeletedEntry = 1 THEN
  940.             WITH Name[1].Entry.RecordHeader DO
  941.                IF NextRecordId <> Null THEN
  942.                   TopRecordId := NextRecordId;
  943.                ELSIF PrevRecordId <> Null THEN
  944.                   TopRecordId := PrevRecordId;
  945.                ELSE
  946.                   TopRecordId := Null;
  947.                END;
  948.             END;
  949.          ELSE
  950.             TopRecordId := Name[1].Entry.RecordId;
  951.          END;
  952.  
  953.          (*--- Delete the selected record ------------------------------*)
  954.  
  955.          File.DeleteRecord (   
  956.             PhoneFileId,
  957.             Name[DeletedEntry].Entry.RecordId,
  958.             ADR (WorkBuffer) );
  959.          File.Close ( PhoneFileId );
  960.  
  961.          (*--- Redisplay the rest of the phone book --------------------*)
  962.  
  963.          ReadPhoneBook ( (TopRecordId <> Null), TopRecordId, TRUE );
  964.       END;
  965.    END DeleteEntry;
  966.  
  967.    (************************** LOCAL ROUTINE ***************************)
  968.  
  969.    PROCEDURE SendName ( Name : ADDRESS );
  970.  
  971.    VAR MsgBuffer  : ARRAY [0..7] OF INTEGER;
  972.  
  973.    BEGIN
  974.       MsgBuffer[0] := Resource.CallBack;
  975.       MsgBuffer[1] := Resource.ApplicationId;
  976.       MsgBuffer[2] := 0;
  977.       MsgBuffer[3] := INTEGER (Name DIV 10000H);
  978.       MsgBuffer[4] := INTEGER (Name MOD 10000H);
  979.       AESApplications.ApplWrite (
  980.          Resource.ApplicationId, SIZE (MsgBuffer), ADR (MsgBuffer) );
  981.    END SendName;
  982.  
  983.    (************************** LOCAL ROUTINE ***************************)
  984.  
  985.    PROCEDURE UpdateLog (
  986.       AddName  : BOOLEAN;
  987.       VAR Name : ARRAY OF CHAR );
  988.  
  989.    CONST
  990.       LogFile   = TRUE;
  991.       UseFormat = TRUE;
  992.       CR        = 015C;
  993.       LF        = 012C;
  994.  
  995.    VAR
  996.       LogFileId   : INTEGER;
  997.       PhoneFileId : File.FileIdType;
  998.       Success     : BOOLEAN;
  999.       Position    : LONGCARD;
  1000.       Time        : CARDINAL;
  1001.       Date        : CARDINAL;
  1002.       Count       : LONGCARD;
  1003.       TempBuffer  : Text.String80;
  1004.       Buffer      : Text.String80;
  1005.       Choice      : INTEGER;
  1006.  
  1007.    BEGIN
  1008.       AESGraphics.GrafMouse ( GEMAESbase.HourGlass, NIL );
  1009.       Buffer[0] := CR;
  1010.       Buffer[1] := CHR (0);
  1011.       Success := Text.ConcatChar ( Buffer, LF, Buffer );
  1012.       IF AddName THEN
  1013.          GEMDOS.GetDate ( Date );
  1014.          Clock.DecodeDate ( Date, UseFormat, TempBuffer );
  1015.          Success := Text.ConcatString ( Buffer, TempBuffer, Buffer );
  1016.          Success := Text.ConcatChar ( Buffer, ' ', Buffer );
  1017.          GEMDOS.GetTime ( Time );
  1018.          Clock.DecodeTime ( Time, UseFormat, TempBuffer );
  1019.          Success := Text.ConcatString ( Buffer, TempBuffer, Buffer );
  1020.          Success := Text.ConcatString ( Buffer, ": Called ", Buffer );
  1021.          Success := Text.ConcatString ( Buffer, Name, Buffer );
  1022.       ELSE
  1023.          Buffer  := ", Length of Call =";
  1024.          Success := Text.ConcatString ( Buffer, DisplayedTime, Buffer );
  1025.          IF Cost > 0 THEN
  1026.             Success := Text.ConcatString ( Buffer, ", Cost = ", Buffer );
  1027.             Success := Text.ConcatString ( Buffer, DisplayedCost, Buffer );
  1028.          END;
  1029.       END;
  1030.       Count := LONGCARD (Text.Length ( Buffer ));
  1031.       IF Disk.SpaceAvailable ( LogDriveNumber, Count ) THEN
  1032.          IF OpenFile ( LogFile, LogFileId, PhoneFileId ) THEN
  1033.             GEMDOS.Seek ( 0, LogFileId, GEMDOS.end, Position );
  1034.             GEMDOS.Write ( LogFileId, Count, ADR (Buffer) );
  1035.             Success := GEMDOS.Close ( LogFileId );
  1036.          END;
  1037.       ELSE
  1038.          AESGraphics.GrafMouse ( GEMAESbase.Arrow, NIL );
  1039.          Choice := AESForms.FormAlert ( 1, DiskFullMsg );
  1040.       END;
  1041.    END UpdateLog;
  1042.  
  1043.    (************************** LOCAL ROUTINE ***************************)
  1044.  
  1045.    PROCEDURE PhoneBookDraw ( Region : Screen.Box );
  1046.  
  1047.    BEGIN
  1048.       ;  (* Already drawn by the window manager *)
  1049.    END PhoneBookDraw;
  1050.  
  1051.    (********************************************************************)
  1052.  
  1053.    PROCEDURE Initialize ();
  1054.  
  1055.    TYPE TedInfoPtrType = POINTER TO Icon.Tedinfo;
  1056.  
  1057.    VAR
  1058.       ObjectPtr  : Icon.ObjectPtr;
  1059.       Index      : CARDINAL;
  1060.       TedInfoPtr : TedInfoPtrType;
  1061.       Ch         : CHAR;
  1062.  
  1063.    BEGIN
  1064.  
  1065.       LogDrive         := Configuration.LogFileName[0];
  1066.       LogDriveNumber   := ORD (LogDrive) - ORD ('A') + 1;
  1067.       PhoneDrive       := Configuration.PhoneFileName[0];
  1068.       PhoneDriveNumber := ORD (PhoneDrive) - ORD ('A') + 1;
  1069.  
  1070.       ObjectPtr := Icon.GetAddress ( Resource.D8PHTIME, Resource.D8TIME );
  1071.       ObjectPtr^.Spec := ADR ( DisplayedTime );
  1072.       ObjectPtr := Icon.GetAddress ( Resource.D8PHTIME, Resource.D8AMOUNT );
  1073.       ObjectPtr^.Spec := ADR ( DisplayedCost );
  1074.  
  1075.       Name[1].ObjectIndex := Resource.D6NAME1;
  1076.       Name[2].ObjectIndex := Resource.D6NAME2;
  1077.       Name[3].ObjectIndex := Resource.D6NAME3;
  1078.       Name[4].ObjectIndex := Resource.D6NAME4;
  1079.       Name[5].ObjectIndex := Resource.D6NAME5;
  1080.       Name[6].ObjectIndex := Resource.D6NAME6;
  1081.       Name[7].ObjectIndex := Resource.D6NAME7;
  1082.       Name[8].ObjectIndex := Resource.D6NAME8;
  1083.       FOR Index := 1 TO 8 DO
  1084.          Name[Index].ObjectPtr := Icon.GetAddress ( 
  1085.             Resource.D6PHONE, Name[Index].ObjectIndex );
  1086.          TedInfoPtr := TedInfoPtrType (Name[Index].ObjectPtr^.Spec);
  1087.          TedInfoPtr^.Text := ADR (Name[Index].Entry.NameText);
  1088.       END;
  1089.  
  1090.       Selector[1].ObjectIndex  := Resource.D6AB;
  1091.       Selector[1].Letter       := 'A';
  1092.       Selector[2].ObjectIndex  := Resource.D6CD;
  1093.       Selector[2].Letter       := 'C';
  1094.       Selector[3].ObjectIndex  := Resource.D6EF;
  1095.       Selector[3].Letter       := 'E';
  1096.       Selector[4].ObjectIndex  := Resource.D6GH;
  1097.       Selector[4].Letter       := 'G';
  1098.       Selector[5].ObjectIndex  := Resource.D6IJ;
  1099.       Selector[5].Letter       := 'I';
  1100.       Selector[6].ObjectIndex  := Resource.D6KL;
  1101.       Selector[6].Letter       := 'K';
  1102.       Selector[7].ObjectIndex  := Resource.D6MN;
  1103.       Selector[7].Letter       := 'M';
  1104.       Selector[8].ObjectIndex  := Resource.D6OP;
  1105.       Selector[8].Letter       := 'O';
  1106.       Selector[9].ObjectIndex  := Resource.D6QR;
  1107.       Selector[9].Letter       := 'Q';
  1108.       Selector[10].ObjectIndex := Resource.D6ST;
  1109.       Selector[10].Letter      := 'S';
  1110.       Selector[11].ObjectIndex := Resource.D6UV;
  1111.       Selector[11].Letter      := 'U';
  1112.       Selector[12].ObjectIndex := Resource.D6WX;
  1113.       Selector[12].Letter      := 'W';
  1114.       Selector[13].ObjectIndex := Resource.D6YZ;
  1115.       Selector[13].Letter      := 'Y';
  1116.       FOR Category := 1 TO 13 DO
  1117.          Selector[Category].ObjectPtr := Icon.GetAddress (
  1118.             Resource.D6PHONE, Selector[Category].ObjectIndex );
  1119.       END;
  1120.       Category := 1;
  1121.       WHILE (GEMDOS.AuxIS ()) DO
  1122.          GEMDOS.AuxIn ( Ch );
  1123.       END;
  1124.    END Initialize;
  1125.  
  1126.    (********************************************************************)
  1127.  
  1128.    PROCEDURE OwnsWindow ( WindowId : INTEGER ) : BOOLEAN;
  1129.  
  1130.    BEGIN
  1131.       IF WindowAllocated THEN
  1132.          RETURN (WindowId = WindowInfo.Id);
  1133.       ELSE
  1134.          RETURN (FALSE);
  1135.       END;
  1136.    END OwnsWindow;
  1137.  
  1138.    (********************************************************************)
  1139.  
  1140.    PROCEDURE Open;
  1141.  
  1142.    CONST
  1143.       FirstName = Null;
  1144.       ValidId   = TRUE;
  1145.  
  1146.    VAR
  1147.       WindowRegion      : Screen.Box;
  1148.       Components        : INTEGER;
  1149.       VirtualRegionSize : Window.Area;
  1150.  
  1151.    BEGIN
  1152.       IF WindowAllocated THEN
  1153.          Window.Top ( WindowInfo.Id );
  1154.       ELSE
  1155.          Icon.GetRegion ( WindowResource, 0, WindowRegion );
  1156.          WindowRegion.Origin.X := 
  1157.             Screen.Center.Origin.X - (WindowRegion.Size.Width DIV 2);
  1158.          WindowRegion.Origin.Y := 
  1159.             Screen.Center.Origin.Y - (WindowRegion.Size.Height DIV 2);
  1160.          VirtualRegionSize.Width  :=
  1161.             Window.Pixel (WindowRegion.Size.Width);
  1162.          VirtualRegionSize.Height :=
  1163.             Window.Pixel (WindowRegion.Size.Height) * 26;
  1164.          IF WindowResource = Resource.D6PHONE THEN
  1165.             Components :=
  1166.                GEMAESbase.Name +
  1167.                GEMAESbase.Closer +
  1168.                GEMAESbase.Mover +
  1169.                GEMAESbase.UpArrow +
  1170.                GEMAESbase.DownArrow;
  1171.          ELSE
  1172.             Components :=
  1173.                GEMAESbase.Name +
  1174.                GEMAESbase.Closer +
  1175.                GEMAESbase.Mover;
  1176.          END;
  1177.          IF Window.Open (
  1178.                Screen.Center,
  1179.                Window.InformationPtr (ADR (WindowInfo)),
  1180.                " Phone Book ",
  1181.                "",   (* No information line *)
  1182.                WindowRegion,
  1183.                VirtualRegionSize,
  1184.                Components,
  1185.                0, 1,                   (* White Background *)
  1186.                WindowResource,
  1187.                PhoneBookDraw ) THEN
  1188.             WindowAllocated := TRUE;
  1189.             IF VirginTool THEN
  1190.                ReadPhoneBook ( ValidId, FirstName, FALSE );
  1191.                VirginTool := FALSE;
  1192.             END;
  1193.          ELSE
  1194.             Window.Unavailable;
  1195.             WindowAllocated := FALSE;
  1196.          END;
  1197.       END;
  1198.       AESGraphics.GrafMouse ( GEMAESbase.Arrow, NIL );
  1199.    END Open;
  1200.  
  1201.    (********************************************************************)
  1202.  
  1203.    PROCEDURE Close;
  1204.  
  1205.    BEGIN
  1206.       IF WindowAllocated THEN
  1207.          IF WindowResource = Resource.D6PHONE THEN
  1208.             DeselectEntries;
  1209.          END;
  1210.          Window.Close ( WindowInfo.Id, Screen.Center );
  1211.          WindowAllocated := FALSE;
  1212.       END;
  1213.    END Close;
  1214.  
  1215.    (********************************************************************)
  1216.  
  1217.    PROCEDURE ProcessMessageEvent ( VAR MsgBuffer : ARRAY OF INTEGER ); 
  1218.  
  1219.    CONST
  1220.       PhoneBookFile = FALSE;
  1221.       RowUp         = 2;
  1222.       RowDown       = 3;
  1223.       ValidId       = TRUE;
  1224.  
  1225.    VAR RecordId : File.RecordIdType;
  1226.  
  1227.    BEGIN
  1228.       IF MsgBuffer[0] = GEMAESbase.AccessoryClose THEN
  1229.          IF WindowAllocated THEN
  1230.             DeselectEntries;
  1231.             Window.Close ( 0, Screen.Center );
  1232.             WindowAllocated := FALSE;
  1233.          END;
  1234.  
  1235.       ELSIF MsgBuffer[0] = GEMAESbase.WindowArrowed THEN
  1236.          IF Name[1].Entry.ValidEntry THEN
  1237.             IF MsgBuffer[4] = RowUp THEN
  1238.                RecordId := Name[1].Entry.RecordHeader.PrevRecordId;
  1239.             ELSE (* MsgBuffer[4] = RowDown *)
  1240.                RecordId := Name[1].Entry.RecordHeader.NextRecordId;
  1241.             END;
  1242.             IF RecordId = Null THEN
  1243.                GEMDOS.ConOut ( Bell );
  1244.             ELSE
  1245.                ReadPhoneBook ( ValidId, RecordId, TRUE );
  1246.                AESGraphics.GrafMouse ( GEMAESbase.Arrow, NIL );
  1247.             END;
  1248.          ELSE
  1249.             GEMDOS.ConOut ( Bell );
  1250.          END;
  1251.          
  1252.       ELSIF MsgBuffer[0] = Resource.MinuteChanged THEN
  1253.          IF WindowResource = Resource.D6PHONE THEN
  1254.             ;  (* Ignore the time update *)
  1255.          ELSE
  1256.             UpdateTime;
  1257.             IF DialedEntry <> Null THEN
  1258.                UpdateCost;
  1259.             END;
  1260.             IF WindowAllocated THEN
  1261.                Window.Redraw ( WindowInfo.Id, WindowInfo.Borders );
  1262.             END;
  1263.          END;
  1264.  
  1265.       ELSE
  1266.          GEMDOS.ConOut ( Bell );
  1267.       END;
  1268.    END ProcessMessageEvent;
  1269.  
  1270.    (********************************************************************)
  1271.  
  1272.    PROCEDURE ProcessButtonEvent ( MouseButton : INTEGER;
  1273.                                   ModifierKey : INTEGER;
  1274.                                   Clicks      : INTEGER );
  1275.  
  1276.    TYPE TedInfoPtrType = POINTER TO Icon.Tedinfo;
  1277.  
  1278.    CONST
  1279.       PhoneBookFile = FALSE;
  1280.       AddName       = TRUE;
  1281.       AddTime       = FALSE;
  1282.  
  1283.    VAR
  1284.       MouseLocation : Screen.PixelCoordinate;
  1285.       MouseState    : INTEGER;
  1286.       KeyboardState : INTEGER;
  1287.       Button        : CARDINAL;
  1288.       FoundButton   : BOOLEAN;
  1289.       Object        : INTEGER;
  1290.       ObjectPtr     : Icon.ObjectPtr;
  1291.       LogFileId     : INTEGER;
  1292.       PhoneFileId   : File.FileIdType;
  1293.       RecordId      : File.RecordIdType;
  1294.       WorkBuffer    : EntryInfo;
  1295.       FoundKey      : BOOLEAN;
  1296.       KeyId         : File.RecordIdType;
  1297.       FoundRecord   : BOOLEAN;
  1298.       FirstLetter   : String1;
  1299.       SecondLetter  : String1;
  1300.  
  1301.    BEGIN
  1302.       AESGraphics.GrafMouseKeyboardState (
  1303.          MouseLocation.X, MouseLocation.Y, MouseState, KeyboardState );
  1304.       IF Icon.Find ( WindowResource, MouseLocation, Object ) THEN
  1305.  
  1306.          (*--- First scan the selector buttons ------------------------*)
  1307.  
  1308.          Button      := 1;
  1309.          FoundButton := FALSE;
  1310.          LOOP
  1311.             IF Object = Selector[Button].ObjectIndex THEN
  1312.                FoundButton := TRUE;
  1313.                EXIT;
  1314.             ELSE
  1315.                INC (Button);
  1316.                IF Button > NumberSelectors THEN
  1317.                   EXIT;
  1318.                END;
  1319.             END;
  1320.          END (* LOOP *);
  1321.          IF FoundButton THEN
  1322.             IF OpenFile ( PhoneBookFile, LogFileId, PhoneFileId ) THEN
  1323.                FirstLetter[0]  := Selector[Button].Letter[0];
  1324.                SecondLetter[0] := CHR (ORD (FirstLetter[0]) + 1);
  1325.                File.Find (
  1326.                   PhoneFileId,
  1327.                   FirstLetter,
  1328.                   "",
  1329.                   ADR (WorkBuffer),
  1330.                   FoundKey,
  1331.                   KeyId,
  1332.                   FoundRecord,
  1333.                   RecordId );
  1334.                IF NOT FoundKey THEN
  1335.                   File.Find (
  1336.                      PhoneFileId,
  1337.                      SecondLetter,
  1338.                      "",  
  1339.                      ADR (WorkBuffer),
  1340.                      FoundKey,
  1341.                      KeyId,
  1342.                      FoundRecord,
  1343.                      RecordId );
  1344.                END;
  1345.                File.Close ( PhoneFileId );
  1346.                ReadPhoneBook ( FoundKey, KeyId, TRUE );
  1347.                Category := Button;
  1348.                IF FoundButton AND (NOT FoundKey) THEN
  1349.                   Selector[Category].ObjectPtr^.State :=
  1350.                      Selector[Category].ObjectPtr^.State + {Icon.Selected};
  1351.                   Icon.Display (
  1352.                      Resource.D6PHONE,
  1353.                      Selector[Category].ObjectIndex,
  1354.                      WindowInfo.Borders );
  1355.                END;
  1356.             END;
  1357.             DeselectEntries;
  1358.  
  1359.          ELSE
  1360.             ObjectPtr := Icon.GetAddress ( WindowResource, Object );
  1361.             IF Icon.Disabled IN ObjectPtr^.State THEN
  1362.                GEMDOS.ConOut ( Bell );
  1363.             ELSE
  1364.  
  1365.                (*--- If the object is a button, "flash" it -------------*)
  1366.  
  1367.                IF ObjectPtr^.Type = GEMAESbase.GraphicButton THEN
  1368.                   ObjectPtr^.State := ObjectPtr^.State + {Icon.Selected};
  1369.                   Icon.Display ( WindowResource, Object, WindowInfo.Borders ); 
  1370.                   ObjectPtr^.State := ObjectPtr^.State - {Icon.Selected};
  1371.                END;
  1372.  
  1373.                IF WindowResource = Resource.D8PHTIME THEN
  1374.  
  1375.                   IF Object = Resource.D8HANGUP THEN
  1376.                      IF DialedEntry <> Null THEN
  1377.                         UpdateLog ( AddTime, "" );
  1378.                      END;
  1379.                      HangUp;
  1380.  
  1381.                   ELSIF Object = Resource.D8CALL THEN
  1382.                      IF DialedEntry = Null THEN
  1383.                         SendName ( Null );
  1384.                      ELSE
  1385.                         UpdateLog ( AddTime, "" );
  1386.                         SendName ( ADR (Name[DialedEntry].Entry.NameText) );
  1387.                      END;
  1388.                      HangUp;
  1389.  
  1390.                   ELSE
  1391.                      GEMDOS.ConOut ( Bell );
  1392.                   END;
  1393.  
  1394.                ELSE (* WindowResource = Resource.D6PHONE *)
  1395.  
  1396.                   IF Object = Resource.D6NAME1 THEN
  1397.                      ProcessName ( 1, Clicks );
  1398.                   ELSIF Object = Resource.D6NAME2 THEN
  1399.                      ProcessName ( 2, Clicks );
  1400.                   ELSIF Object = Resource.D6NAME3 THEN
  1401.                      ProcessName ( 3, Clicks );
  1402.                   ELSIF Object = Resource.D6NAME4 THEN
  1403.                      ProcessName ( 4, Clicks );
  1404.                   ELSIF Object = Resource.D6NAME5 THEN
  1405.                      ProcessName ( 5, Clicks );
  1406.                   ELSIF Object = Resource.D6NAME6 THEN
  1407.                      ProcessName ( 6, Clicks );
  1408.                   ELSIF Object = Resource.D6NAME7 THEN
  1409.                      ProcessName ( 7, Clicks );
  1410.                   ELSIF Object = Resource.D6NAME8 THEN
  1411.                      ProcessName ( 8, Clicks );
  1412.  
  1413.                   ELSIF Object = Resource.D6TIMCAL THEN
  1414.                      DialedEntry := Null;
  1415.                      DeselectEntries;
  1416.                      TimeCall;
  1417.  
  1418.                   ELSIF Object = Resource.D6DIAL THEN
  1419.                      DialedEntry := SelectedEntry;
  1420.                      UpdateLog ( AddName, Name[DialedEntry].Entry.NameText );
  1421.                      DeselectEntries;
  1422.                      Dial;
  1423.  
  1424.                   ELSIF Object = Resource.D6ADD THEN
  1425.                      DeselectEntries;
  1426.                      AddEntry;
  1427.    
  1428.                   ELSIF Object = Resource.D6DELETE THEN
  1429.                      DeletedEntry := SelectedEntry;
  1430.                      DeselectEntries;
  1431.                      DeleteEntry;
  1432.  
  1433.                   ELSIF Object = Resource.D6CALL THEN
  1434.                      IF SelectedEntry = NoSelectedEntries THEN
  1435.                         SendName ( Null );
  1436.                      ELSE
  1437.                         SendName ( ADR (Name[SelectedEntry].Entry.NameText) );
  1438.                      END;
  1439.                      DeselectEntries;
  1440.                      Icon.Display (
  1441.                         Resource.D6PHONE, Resource.D6CALL, WindowInfo.Borders ); 
  1442.  
  1443.                   ELSE
  1444.                      GEMDOS.ConOut ( Bell );
  1445.                   END;
  1446.                END;
  1447.             END;
  1448.          END;
  1449.       ELSE
  1450.          GEMDOS.ConOut ( Bell );
  1451.       END;
  1452.       AESGraphics.GrafMouse ( GEMAESbase.Arrow, NIL );
  1453.    END ProcessButtonEvent;
  1454.  
  1455.    (********************************************************************)
  1456.  
  1457.    PROCEDURE ProcessKeyboardEvent ( Key         : INTEGER;
  1458.                                     ModifierKey : INTEGER );
  1459.    BEGIN
  1460.       GEMDOS.ConOut ( Bell );
  1461.    END ProcessKeyboardEvent;
  1462.  
  1463.  
  1464. BEGIN
  1465.    WindowAllocated := FALSE;
  1466.    WindowResource  := Resource.D6PHONE;
  1467.    SelectedEntry   := NoSelectedEntries;
  1468.    VirginTool      := TRUE;
  1469.    PreviousTime    := 0;
  1470. END PhoneBook.
  1471.  
  1472.